/*****  其他说明补充
 *      该任务stack_size给的是0x1000,建议适当增大一点
 *      该任务的优先级是 osPriorityNormal + 1 = 25
 *      lv_display_init() 和 lvgl_display_open() 前面初始化部分是一样的，如果open用成开机显示，init前面的初始化部分得去掉
 */

#include "lvgl_display.h"

/*********** 一些需要的资源 ***********/
// 定时器句柄：lvgl框架软件定时器需要硬件定时器提供1ms时间基准
static timer_handle_t timer_handle = NULL;             
// 目前lvgl配置的是16位色深（因为1位太多bug了），使用的是RGB565格式
static uint8_t buf_16bit[SSD1306_WIDTH * SSD1306_HEIGHT *2]; /*RGB565格式缓冲区，每像素2字节*/
// 三个动态标签，放在全局变量方便写更改接口(其实不用....因为几个接口函数不需要这几个参数)
lv_obj_t *label_status;
lv_obj_t *label_text ;
lv_obj_t *label_emoji;
lv_display_t *disp;


/************** 屏幕驱动配置相关 *****************/

#define I2C_MASTER_ADDR                   0x0
#define I2C_SET_BAUDRATE                  400000
#define I2C_MASTER_PIN_MODE               2

static void app_i2c_init_pin(void)
{
    /* I2C pinmux. */
    uapi_pin_set_mode(15, I2C_MASTER_PIN_MODE);
    uapi_pin_set_mode(16, I2C_MASTER_PIN_MODE);       
    uapi_pin_set_pull(15, PIN_PULL_TYPE_UP);
    uapi_pin_set_pull(16, PIN_PULL_TYPE_UP);
}


/**************** lvgl适配相关 ******************/

// lvgl框架flush函数和ssd1306驱动函数适配的两个函数
void ssd1306_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); // 设置绘制区域
void ssd1306_write_data_16bit(uint8_t *data, uint32_t len);                  // 绘制数据

// lvgl刷新定时器回调
void TimerCallback(uintptr_t data)
{
    unused(data);
    lv_tick_inc(1); // 告诉LVGL时间过去1毫秒
    uapi_timer_start(timer_handle, 1000, TimerCallback, 0); // 递归调用，提供1ms时间基准
}
// lvgl刷新函数,参数：显示设备指针，刷新区域，像素数据指针
static void disp_flush(lv_display_t *disp_drv, const lv_area_t *area, uint8_t *px_map)
{
    // osal_printk("disp_flush called: area(%d,%d)-(%d,%d), size=%d bytes\n", 
    //             area->x1, area->y1, area->x2, area->y2, 
    //             (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2);
    
    ssd1306_set_window(area->x1, area->y1, area->x2, area->y2); // 设置绘制区域
    ssd1306_write_data_16bit(px_map, (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) *2 ); // 每个像素2字节（16位色深）
    lv_display_flush_ready(disp_drv);  // 通知lvgl刷新完成
}




/************** 初始化函数（总） ***************/

void lvgl_display_init(void)
{
    // // 屏幕初始化
    // app_i2c_init_pin();
    // errcode_t ret = uapi_i2c_master_init(1, I2C_SET_BAUDRATE, I2C_MASTER_ADDR);
    // if (ret != 0) {
    //     printf("i2c init failed, ret = %0x\r\n", ret);
    // }
    // ssd1306_Init();
    // ssd1306_Fill(Black);
    // ssd1306_UpdateScreen();  // 初始化后更新一次屏幕
    // // lvgl
    // lv_init();

    // lv_display_t *disp = lv_display_create(SSD1306_WIDTH, SSD1306_HEIGHT);
    // lv_display_set_flush_cb(disp, disp_flush);
    // lv_display_set_buffers(disp, buf_16bit, NULL, sizeof(buf_16bit), LV_DISPLAY_RENDER_MODE_PARTIAL);
    // // 定时器
    // uapi_timer_init();                                             // 初始化定时器模块
    // uapi_timer_adapter(1, TIMER_1_IRQN, 1); // 配置lvgl定时器适配器
    // uapi_timer_create(1, &timer_handle);                 // 创建lvgl定时器，并获取定时器句柄
    // uapi_timer_start(timer_handle, 1000, TimerCallback, 0);     // 启动lvgl定时器，设置触发时间和回调函数

    // 获取显示设备上的当前活动屏幕
    lv_obj_t *active_screen = lv_display_get_screen_active(disp);
    if (active_screen) {
        // 清空屏幕上的所有子对象
        lv_obj_clean(active_screen);
        osal_printk("Active screen cleaned successfully.\n");
    }


// 下面是lvgl界面元素的创建和布局

    
    /******************* 顶部状态栏 **************************/

    // 创建顶部状态栏容器（0，0）->(127，30)
    uint16_t container_status_width = 127 - 0 + 1; // 128像素
    uint16_t container_status_height = 30 - 0 + 1; // 31像素

    lv_obj_t *container_status = lv_obj_create(lv_scr_act());
    lv_obj_set_size(container_status, container_status_width, container_status_height);
    lv_obj_set_pos(container_status, 0, 0);
 

    // 取消容器之间的间隔
    lv_obj_set_style_pad_all(container_status, 0, 0); // 设置内边距为0
    lv_obj_set_style_pad_row(container_status, 0, 0);
    lv_obj_set_style_pad_column(container_status, 0, 0);


    // 在顶部容器中添加内容

    // 语音状态
    label_status = lv_label_create(container_status);
    lv_label_set_text(label_status, "说话中...");
    lv_obj_center(label_status);
    lv_obj_set_y(label_status, lv_obj_get_y(label_status) - 2); // 向上移动2像素
    lv_obj_set_style_bg_opa(container_status, 0, 0); 
    // 网络状态（wifi）
    lv_obj_t *label_network = lv_label_create(container_status);
    lv_label_set_text(label_network, FONT_AWESOME_WIFI);
    lv_obj_align(label_network, LV_ALIGN_LEFT_MID, 5, -4); // 左侧中间对齐，x偏移5像素，y偏移0像素
    lv_obj_set_style_text_font(label_network, &font_awesome_14_1, 0);
    // // 小星闪logo（不用了，图模取得有的问题）
    // lv_obj_t * img = lv_image_create(container_status);
    // lv_image_set_src(img, &logo_img_16x16);
    // lv_obj_set_x(img, -3); // 向左挪
    //和下面区域的分隔线
    lv_obj_t *label_ddl = lv_label_create(container_status);
    lv_label_set_text(label_ddl, "- - - - - - - - - - - -"); 
    lv_obj_align(label_ddl, LV_ALIGN_BOTTOM_MID, 0, 0); // 将标签对齐到容器的底部居中位置
    

    /******************* 顶部状态栏 **************************/




    /******************* 返回流动文本 **************************/


    // 文本区域（31，15）->(127，63)
    uint16_t text_width = 127 - 31 + 1; // 97像素
    uint16_t text_height = 63 - 15 + 1; // 49像素
    lv_obj_t *container_text = lv_obj_create(lv_scr_act());
    
    lv_obj_set_size(container_text, text_width, text_height);
    lv_obj_set_pos(container_text, 31, 15);
    lv_obj_set_style_bg_opa(container_text, 0, 0); // 透明背景,这个必须调用，不然会出问题(花屏)

    // 在容器内创建标签并居中
    label_text = lv_label_create(container_text);
    // 设置标签文本内容
    lv_label_set_text(label_text, "我是小智，这是在做滚动测试哦abcd");
    //lv_obj_set_style_text_font(label_text, &font_puhui_14_1, 0);
    // 设置动画模式
    lv_label_set_long_mode(label_text, LV_LABEL_LONG_MODE_SCROLL_CIRCULAR); // 循环滚动模式
    lv_obj_set_style_anim_duration(label_text, 1500, 0);// 设置滚动动画时长（毫秒）
    // 设置标签位置
    lv_obj_set_width(label_text, text_width - 10);// 设置标签宽度（小于容器宽度以启用滚动）
    lv_obj_set_height(label_text, 24);// 设置标签高度
    lv_obj_center(label_text); // 在容器内居中
    lv_obj_set_y(label_text, lv_obj_get_y(label_text) + 4); // 向下移动2像素
    
    
    /******************* 返回流动文本 **************************/




    /******************* 表情显示区 **************************/

    // 表情区域（0，16） ->(30，63)
    uint16_t emoji_width  = 30 - 0 + 1; 
    uint16_t emoji_height = 63 - 16 + 1;
    lv_obj_t *container_emoji = lv_obj_create(lv_scr_act());
    
    lv_obj_set_size(container_emoji, emoji_width, emoji_height);
    lv_obj_set_pos(container_emoji, 0, 16);

    // 创建表情标签
    label_emoji = lv_label_create(container_emoji);
    lv_label_set_text(label_emoji, FONT_AWESOME_NEUTRAL);
    lv_obj_center(label_emoji);
    lv_obj_set_style_text_font(label_emoji, &font_awesome_20_4, 0);

    /******************* 表情显示区 **************************/
    

    // 循环执行lvgl刷新               不要喷我在这拉屎，注释部分为测试几个接口的代码，
    // uint16_t awesome_flag = 1;   //循环部分你可以在这个oled的线程任务里去处理，参考test.c
    // uint32_t loop_time = 0;
    while (1)
    {
        // if(loop_time % 50 == 0){
        //     if(awesome_flag % 2 == 0){
        //         label_status_listening();
        //         label_text_change("我是小智，正在聆听您的指令哦！");
        //         label_emoji_change(FONT_AWESOME_LOVING);
        //     } 
        //     else{
        //         label_status_idle();
        //         label_text_change("我是小智，我难道真的没事干吗？");
        //         label_emoji_change(FONT_AWESOME_COOL);
        //     }
        //     awesome_flag++;
        // }
        
        lv_timer_handler(); // lvgl刷新句柄
        uapi_watchdog_kick();
        osal_msleep(33);   
        // loop_time++;  
    }


}

// 备用方案或者开机显示      WiFi连接中...
//                     星闪logo + 星闪小智 

void lvgl_display_open(void)
{
     // 屏幕初始化
    app_i2c_init_pin();
    errcode_t ret = uapi_i2c_master_init(1, I2C_SET_BAUDRATE, I2C_MASTER_ADDR);
    if (ret != 0) {
        printf("i2c init failed, ret = %0x\r\n", ret);
    }
    ssd1306_Init();
    ssd1306_Fill(Black);
    ssd1306_UpdateScreen();  // 初始化后更新一次屏幕
    // lvgl
    lv_init();

    disp = lv_display_create(SSD1306_WIDTH, SSD1306_HEIGHT);
    lv_display_set_flush_cb(disp, disp_flush);
    lv_display_set_buffers(disp, buf_16bit, NULL, sizeof(buf_16bit), LV_DISPLAY_RENDER_MODE_PARTIAL);// 最后一个参数是节省ram的渲染模式
    // 定时器
    uapi_timer_init();                                             // 初始化定时器模块
    uapi_timer_adapter(1, TIMER_1_IRQN, 1); // 配置lvgl定时器适配器
    uapi_timer_create(1, &timer_handle);                 // 创建lvgl定时器，并获取定时器句柄
    uapi_timer_start(timer_handle, 1000, TimerCallback, 0);     // 启动lvgl定时器，设置触发时间和回调函数

    // 星闪logo+星闪小智

    // 创建图像对象，父对象可以是任何容器或屏幕
    lv_obj_t * img = lv_image_create(lv_scr_act());
    
    // 设置图像数据源为logo.c中定义的图模数据结构体
    lv_image_set_src(img, &logo_img_32x32); // 假设你的图模数据结构体名为emoji_img
    
    // 设置图像位置（可以根据需要调整）
    lv_obj_center(img); // 居中显示
    lv_obj_set_x(img, -32); // 向左移动32像素

    // “星闪小智”区域（31+16，0） ->(127，63)
    uint16_t open_width  = 127 - 31-16 + 1; 
    uint16_t open_height = 63 - 0 + 1;
    lv_obj_t *container_open = lv_obj_create(lv_scr_act());
    
    lv_obj_set_size(container_open, open_width, open_height);
    lv_obj_set_pos(container_open, 16+31, 0);

    
    lv_obj_t *label_open = lv_label_create(container_open);
    lv_label_set_text(label_open, "星闪小智");
    lv_obj_center(label_open);
      
    lv_obj_t *label_open_status = lv_label_create(lv_scr_act());
    lv_label_set_text(label_open_status, "WiFi连接中...");
    lv_obj_center(label_open_status); // 居中显示
    lv_obj_set_y(label_open_status, -25);

        uint32_t loop_time = 0;
        while (1)
    {
        // if(loop_time % 50 == 0){
        //     if(awesome_flag % 2 == 0){
        //         label_status_listening();
        //         label_text_change("我是小智，正在聆听您的指令哦！");
        //         label_emoji_change(FONT_AWESOME_LOVING);
        //     } 
        //     else{
        //         label_status_idle();
        //         label_text_change("我是小智，我难道真的没事干吗？");
        //         label_emoji_change(FONT_AWESOME_COOL);
        //     }
        //     awesome_flag++;
        // }
        if(loop_time == 150){// 5s
            lvgl_display_init();
        }
        
        lv_timer_handler(); // lvgl刷新句柄
        uapi_watchdog_kick();
        osal_msleep(33);   
         loop_time++;  
    }

}

/************ 动态标签更改接口 *************/

// 更改语音状态标签: 其实只有两种状态转化： 说话中...  和 聆听中... 
void label_status_listening(void)
{
    lv_label_set_text(label_status, "聆听中...");
}
void label_status_speaking(void)
{
    lv_label_set_text(label_status, "说话中...");
}
void label_status_idle(void)
{
    lv_label_set_text(label_status, "空闲中...");
}

// 更改语音文本标签：懒得写@param注释了，点进来看就好,参数即更改的文本内容
void label_text_change(const char *text)
{
    lv_label_set_text(label_text, text); // 因为只有一个text标签，所有就只这么写就行 
}

// 更改表情标签：参数即更改的表情内容
void label_emoji_change(const char *emoji)
{

    lv_label_set_text(label_emoji, emoji); // emoji标签内容有awesome字体库支持,格式类似FONT_AWESOME_NEUTRAL
}

/****************** ssd1306适配函数实现 **********************/

// 全局变量存储当前绘制区域
static lv_area_t current_area = {0};

void ssd1306_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
    // 保存当前绘制区域信息
    current_area.x1 = x1;
    current_area.y1 = y1;
    current_area.x2 = x2;
    current_area.y2 = y2;
    
    osal_printk("ssd1306_set_window: (%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
}


void ssd1306_write_data_16bit(uint8_t *data, uint32_t len)
{
    // LVGL使用RGB565格式，每个像素2字节
    // SSD1306是单色显示器，需要将RGB565转换为单色
    
    uint32_t pixel_count = len / 2; // RGB565格式，每像素2字节
    uint16_t *pixel_data = (uint16_t*)data;
    
    // 计算区域尺寸
    uint16_t area_width = current_area.x2 - current_area.x1 + 1;
    uint16_t area_height = current_area.y2 - current_area.y1 + 1;
    
    osal_printk("ssd1306_write_data: len=%d, pixels=%d, area=%dx%d\n", 
                len, pixel_count, area_width, area_height);
    
    // 将RGB565像素转换为单色并绘制到指定区域
    for (uint32_t i = 0; i < pixel_count; i++) {
        uint16_t pixel = pixel_data[i];
        
        // 处理字节交换（如果LVGL配置了LV_COLOR_16_SWAP）
        #if LV_COLOR_16_SWAP
        pixel = ((pixel & 0xFF) << 8) | ((pixel >> 8) & 0xFF);
        #endif
        
        // 从RGB565提取RGB分量
        uint8_t r = (pixel >> 11) & 0x1F;  // 5位红色
        uint8_t g = (pixel >> 5) & 0x3F;   // 6位绿色  
        uint8_t b = pixel & 0x1F;          // 5位蓝色
        
        // 转换为8位RGB值
        r = (r * 255) / 31;
        g = (g * 255) / 63;
        b = (b * 255) / 31;
        
        // 计算亮度（使用标准亮度公式）
        uint8_t brightness = (uint8_t)(0.299 * r + 0.587 * g + 0.114 * b);
        
        // 计算像素在区域内的相对位置
        uint16_t rel_x = i % area_width;
        uint16_t rel_y = i / area_width;
        
        // 计算在屏幕上的绝对位置
        uint16_t abs_x = current_area.x1 + rel_x;
        uint16_t abs_y = current_area.y1 + rel_y;
        
        // 确保坐标在屏幕范围内
        if (abs_x < SSD1306_WIDTH && abs_y < SSD1306_HEIGHT) {
            // 使用阈值判断是否显示像素（可以调整阈值）
            if (brightness > 128) {  // 亮度阈值，可以调整
                ssd1306_DrawPixel(abs_x, abs_y, Black);
            } else {
                ssd1306_DrawPixel(abs_x, abs_y, White);
            }
        }
    }
    
    osal_printk("ssd1306_write_data: processed %d pixels, updating screen\n", pixel_count);
    
    // 更新屏幕显示
    ssd1306_UpdateScreen();


}


